package gokyesil.game2d.actors;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Array;

public class Map extends Table
{
	public final int BLOCK_SIZE = 25; 
	public boolean boolMap[][];
	public World physWorld;
	public World backupWorld;
	public ShapeRenderer shapeRenderer;
	private boolean isGridVisible;
	private int slideX;
	private int slideY;
	private int blockNumberX;
	private int blockNumberY;
	private MapPlayer player;
	private MapBlock[] blockList;
	private MapFinish finish;
	private MapChain chain;
	private MapPlayer backupPlayer;
	private MapFinish backupFinish;
	private MapChain backupChain;
	public Map(float x, float y, float width, float height)
	{
		super();
		this.setPosition(x, y);
		this.setWidth(width);
		this.setHeight(height);
		this.setTransform(true);
		physWorld = new World(new Vector2(0,0), true);
		boolMap = new boolean[100][100];
		for(int i=0; i<100; i++)
			for(int j=0; j<100; j++)
				boolMap[i][j] = false;
		shapeRenderer = new ShapeRenderer();
		isGridVisible = true;
		slideX = 0;
		slideY = 0;
		player = null;
		this.setTransform(true);
	}
	public void act (float delta)
	{
		physWorld.step(delta, 1, 1);
		if(player != null)
		{
			player.getBody().applyLinearImpulse(new Vector2(player.getBody().getLinearVelocity()).nor().scl(0.001f), player.getBody().getPosition(), true);
			player.getBody().applyForceToCenter(new Vector2(0,-100), true);
		}
		super.act(delta);	
		
	}
	public void deleteBlock(MapBlock block)
	{
		Body body = block.getBody();
		int coordX = (int) (block.getX()/BLOCK_SIZE);
		int coordY = (int) (block.getY()/BLOCK_SIZE);
		if(coordX < slideX || coordY < slideY || !boolMap[coordX][coordY]) return;
		int sclX = (int) (block.getWidth()/BLOCK_SIZE);
		int sclY = (int) (block.getHeight()/BLOCK_SIZE);
		if(chain != null && (block instanceof MapPlayer || block == chain.block )) 
		{
			this.player = null;
			this.removeChain();
		}
		for(int i=0; i<sclX; i++)
			for(int j=0; j<sclY; j++)
				boolMap[coordX+i][coordY+j] = false;
		block.remove();
		this.removeActor(block);
		if(block instanceof MapFinish) this.finish = null;
		physWorld.destroyBody(body);
	}
	public void draw(Batch batch, float parentAlpha)
	{
		super.draw(batch, parentAlpha);
		if(!this.isGridVisible) return;
		applyTransform(batch, computeTransform());
		shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
		shapeRenderer.setTransformMatrix(batch.getTransformMatrix());
		shapeRenderer.setColor(0, 0, 0, 1);
		shapeRenderer.updateMatrices();
		if(isGridVisible)
		{
			for(int i=slideX; i<=slideX+blockNumberX; i++)
			{
				for(int j=slideY; j<=slideY+blockNumberY; j++)
				{
					batch.end();
					shapeRenderer.begin(ShapeType.Line);
					shapeRenderer.rect(i*BLOCK_SIZE, j*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
					shapeRenderer.end();
					batch.begin();
					
				}
			}
		}
		resetTransform(batch);
	}
	public void toggleGridVisibility()
	{
		this.isGridVisible = !this.isGridVisible;
	}
	public void slideX(boolean isRight) 
	{
		if(!isRight && this.slideX > 0)
		{
			this.setPosition(this.getX()+BLOCK_SIZE*this.getScaleX(), this.getY());
			this.slideX--;
		}
		if(isRight && 100-this.slideX > blockNumberX)
		{
			this.setPosition(this.getX()-BLOCK_SIZE*this.getScaleX(), this.getY());
			this.slideX++;
		}
	}
	public void slideY(boolean isUpper) 
	{
		if(!isUpper && this.slideY > 0)
		{
			this.setPosition(this.getX(), this.getY()+BLOCK_SIZE*this.getScaleY());
			this.slideY--;
		}
		if(isUpper && 100-this.slideY > blockNumberY)
		{
			this.setPosition(this.getX(), this.getY()-BLOCK_SIZE*this.getScaleY());
			this.slideY++;
		}
	}
	public void zoom(boolean isZoomIn)
	{
		if(isZoomIn && this.getScaleX() < 2.0f)
		{
			this.scaleBy(0.1f);
			this.updateBlockNumber();
			this.setPosition(this.getX()-this.slideX*BLOCK_SIZE*0.1f,this.getY()-this.slideY*BLOCK_SIZE*0.1f);
		}
		if(!isZoomIn && this.getScaleY() > 0.5f)
		{
			this.scaleBy(-0.1f);
			this.updateBlockNumber();
			this.setPosition(this.getX()+this.slideX*BLOCK_SIZE*0.1f,this.getY()+this.slideY*BLOCK_SIZE*0.1f);
		}
	}
	public void updateBlockNumber()
	{
		this.blockNumberX = (int) (this.getWidth()/(this.BLOCK_SIZE*this.getScaleX()));
		this.blockNumberY = (int) (this.getHeight()/(this.BLOCK_SIZE*this.getScaleY()));
		
	}
	public void resize(float width, float height)
	{
		this.setWidth(width);
		this.setHeight(height);
		this.updateBlockNumber();
	}
	public void getClones()
	{
		Array<Actor> array = this.getChildren();
		blockList = new MapBlock[array.size];
		backupWorld = new World(new Vector2(0,0), true);
		if(player != null) this.backupPlayer = (MapPlayer) this.player.clone(backupWorld);
		if(finish != null) this.backupFinish = (MapFinish) this.finish.clone(backupWorld);
		MapBlock chainedBlock = null;
		for(int i=0; i<array.size; i++)
			if(array.get(i) instanceof MapBlock && !(array.get(i) instanceof MapPlayer) &&!(array.get(i) instanceof MapChain) && !(array.get(i) instanceof MapFinish))
			{
				if(this.chain != null && ((MapBlock)array.get(i)) == this.chain.block) 
					chainedBlock = blockList[i] = ((MapBlock)array.get(i)).clone(backupWorld);
				else
					blockList[i] = ((MapBlock)array.get(i)).clone(backupWorld);
			}
		if(this.chain != null && chainedBlock != null && player != null)
			this.backupChain = this.chain.clone(backupPlayer,chainedBlock,backupWorld);
	}
	public void reset()
	{
		this.clear();
		physWorld.dispose();
		physWorld = backupWorld;
		for(int i=0; i<blockList.length; i++)
			if(blockList[i] != null)
				this.addActor(blockList[i]);
		if(backupPlayer != null) 
		{
			player = backupPlayer;
			this.addActor(backupPlayer);
		}
		if(backupChain != null)
		{
			chain = backupChain;
			this.addActor(backupChain);
		}
		if(backupFinish != null)
		{
			finish = backupFinish;
			this.addActor(backupFinish);
		}
	}
	public boolean addBlock(ButtonStyle style, float x, float y, Blocks type)
	{
		if(x < 0 || y < 0 || x>this.getWidth() || y>this.getHeight())
			return false;
		if(type == Blocks.Player) if(this.player != null) deleteBlock(player);
		if(type == Blocks.Finish) if(this.finish != null) deleteBlock(finish);
		float newBlockSize = BLOCK_SIZE*this.getScaleX();
		int coordX = (int) (x/newBlockSize);
		int coordY = (int) (y/newBlockSize);

    	float width = ((TextureRegionDrawable)style.up).getRegion().getTexture().getWidth();
    	float height = ((TextureRegionDrawable)style.up).getRegion().getTexture().getHeight();
		int sclX = (int) (width/BLOCK_SIZE);
		int sclY = (int) (height/BLOCK_SIZE);
		float scaledX = x/newBlockSize;
		float scaledY = y/newBlockSize;
		int newCoordX;
		int newCoordY;
		if(sclX % 2 == 1)
			newCoordX = coordX-((int)(sclX/2));
		else
			if(scaledX - coordX > 0.5f)
				newCoordX = coordX-sclX/2+1;
			else
				newCoordX = coordX-sclX/2;
		if(sclY % 2 == 1)
			newCoordY = coordY-((int)(sclY/2));
		else
			if(scaledY - coordY > 0.5f)
				newCoordY = coordY-sclY/2+1;
			else
				newCoordY = coordY-sclY/2;
		if(newCoordX < slideX || newCoordY < slideY || newCoordX > slideX+blockNumberX || newCoordY > slideY+blockNumberY)
			return false;
		for(int i=0; i<sclX; i++)
			for(int j=0; j<sclY; j++)
				if (boolMap[newCoordX+i][newCoordY+j])
					return false;
					
    	int newX = newCoordX*BLOCK_SIZE;
    	int newY = newCoordY*BLOCK_SIZE;
		for(int i=0; i<sclX; i++)
			for(int j=0; j<sclY; j++)
				boolMap[newCoordX+i][newCoordY+j] = true;
		
		MapBlock block;
		if(type == Blocks.Player)
		{
			this.player = new MapPlayer(style,newX,newY,width,physWorld);
			block = this.player;
		}
		else if(type == Blocks.Finish)
		{
			this.finish = new MapFinish(style,newX,newY,width,physWorld);
			block = this.finish;
		}
		else
		{
			block = new MapBlock(style,newX,newY,width,height,physWorld);
		}
		this.addActor(block);
		return true;
	}
	public boolean addChain(Texture texture, float x, float y) 
	{
		if(x < 0 || y < 0 || x>this.getWidth() || y>this.getHeight())
			return false;
		if(this.player == null) return false;
		
		
		Actor actor = this.hit(x, y, true);
		if(actor instanceof MapBlock && !(actor instanceof MapPlayer) &&!(actor instanceof MapChain) && !(actor instanceof MapFinish))
		{
			if(this.chain != null)
				removeChain();
			this.chain = new MapChain(texture, player,(MapBlock)actor,physWorld);
			this.add(chain);
			return true;
		}
		else
			return false;
	}
	public void removeChain() 
	{
		if(this.chain == null) return;
		chain.delete(physWorld);
		this.removeActor(chain);
		chain = null;
	}
}
